import time
from utils.common_import import *
from .model import PAI_PROJECT_JOB, IntervalQuerySchema
from utils.ext import inner_db
from app.containers.containers import get_jobs_status
from .model import PlatformUsers

from .dashboard import get_time_day_edge_millsecond, make_zero_time_series,\
    HOUR_UNIT_TIME_MILL_SECOND, DAY_UNIT_TIME_MILL_SECOND, TOP_NUM

#获取一段时间内提交的任务数统计
class JobsView(Resource):
    # @jwt_required()
    @request_arg_check(IntervalQuerySchema(), location="args")
    @exception_response()
    def get(self):
        interval = current_schema_instance["query_interval"]
        time_rage = get_time_day_edge_millsecond(interval)
        begin_day_time = time_rage["start_day"]

        #获取任务按照时间升序
        records = inner_db.session.query(PAI_PROJECT_JOB.job_name, PAI_PROJECT_JOB.create_time).\
                    filter(PAI_PROJECT_JOB.create_time >= begin_day_time).\
                    order_by(PAI_PROJECT_JOB.create_time).all()

        #处理任务为空情形
        if not records:
            logger.info("there is no record in {} days".format(interval))
            return  make_success_response(make_zero_time_series(begin_day_time, interval))

        jobs_time_list = self._count_jobs_by_interval(begin_day_time, records)
        logger.info("jobs_time_list is {}".format(jobs_time_list))

        return make_success_response(jobs_time_list)

    def _count_jobs_by_interval(self, begin_day_time, records):
        jobs_time_map = {}
        start = begin_day_time
        for record in records:
            job_create_time = record[1]

            #获取的任务本身是升序的，这里只要找到边界就好
            while start < job_create_time:
                start += DAY_UNIT_TIME_MILL_SECOND

            # start 已经移动到任务时间的右侧， 获取左侧时间作为统计时间
            target = start - DAY_UNIT_TIME_MILL_SECOND

            jobs_time_map.setdefault(str(target), 0)
            jobs_time_map[str(target)] += 1

        jobs_time_list = []
        for time_stamp in jobs_time_map:
            jobs_time_list.append([int(time_stamp), jobs_time_map[time_stamp]])

        return jobs_time_list

#统计一段时间内失败和成功任务数
class JobStatusView(Resource):
    # @jwt_required()
    @request_arg_check(IntervalQuerySchema(), location="args")
    @exception_response()
    def get(self):
        interval = current_schema_instance["query_interval"]
        time_rage = get_time_day_edge_millsecond(interval)
        begin_day_time = time_rage["start_day"]

        #获取任务按照时间升序
        records = inner_db.session.query(PAI_PROJECT_JOB.job_name, PAI_PROJECT_JOB.create_time).\
                    filter(PAI_PROJECT_JOB.create_time >= begin_day_time).\
                    order_by(PAI_PROJECT_JOB.create_time).all()

        #处理任务为空情形
        if not records:
            logger.info("there is no record in {} days".format(interval))
            return  make_success_response(make_zero_time_series(begin_day_time, interval))

        #获取时间点对应的成功失败任务数
        jobs_time_map = self._count_jobs_by_interval(begin_day_time, records)

        #[[时间戳，成功任务数， 失败任务数]]
        jobs_time_list = [[time_stamp,
                            jobs_time_map[time_stamp][0],
                            jobs_time_map[time_stamp][1]
                            ] for time_stamp in jobs_time_map
                          ]

        return make_success_response(jobs_time_list)

    def _get_jobs_status_info(self, records):
        #获取任务状态
        job_name_list = [record[0] for record in records]

        jobs_status = get_jobs_status(job_name_list)
        job_name_status_map = {}

        #获取已经结束的任务的状态，成功或者失败
        for job in jobs_status:
            if job.state() not in ["SUCCESS", "FAILED", "STOPPED"]:
                continue

            if job.state() == "SUCCESS":
                job_name_status_map[job.name()] = "SUCCESS"
            else:
                job_name_status_map[job.name()] = "FAILED"

        logger.info("job_name_status_map is {}".format(job_name_status_map))

        return job_name_status_map

    def _count_jobs_by_interval(self, begin_day_time, records):
        #获取任务状态
        job_name_status_map = self._get_jobs_status_info(records)

        jobs_time_map = {}
        start = begin_day_time
        for record in records:
            job_name = record[0]
            job_create_time = record[1]

            #获取的任务本身是升序的，这里只要找到边界就好
            while start < job_create_time:
                start += DAY_UNIT_TIME_MILL_SECOND

            # start 已经移动到任务时间的右侧， 获取左侧时间作为统计时间
            target = start - DAY_UNIT_TIME_MILL_SECOND
            if job_name in job_name_status_map:
                jobs_time_map.setdefault(target, [0, 0])
                if job_name_status_map[job_name] == "SUCCESS":
                    jobs_time_map[target][0] +=  1
                else:
                    jobs_time_map[target][1] += 1

        return jobs_time_map

#单个任务时长Top
class TopJobsHourView(Resource):
    # @jwt_required()
    @request_arg_check(IntervalQuerySchema(), location="args")
    @exception_response()
    def get(self):
        interval = current_schema_instance["query_interval"]
        time_rage = get_time_day_edge_millsecond(interval)
        begin_time = time_rage["start_day"]

        jobs_name_list = inner_db.session.query(PAI_PROJECT_JOB.job_name).\
            filter(PAI_PROJECT_JOB.create_time >= begin_time).all()

        #处理任务为空情形
        if not jobs_name_list:
            logger.info("there is no record in {} days".format(interval))
            return  make_success_response([])

        top_jobs_list=self._get_top_durtaion_jobs(jobs_name_list)

        return make_success_response(top_jobs_list)

    def _get_jobs_durtaion_info(self, records):
        jobs_name_list = [job_tuple[0] for job_tuple in records]
        logger.info(jobs_name_list)

        jobs_status = get_jobs_status(jobs_name_list)
        logger.info(jobs_status)

        jobs_hours = {}
        for job in jobs_status:
            # job_start_time = job['firstRequestTimestamp']
            # #运行任务以当前任务作为结束时间统计时长
            # if job['frameworkCompletedTimestamp']:
            #     job_end_time = job['frameworkCompletedTimestamp']
            # else:
            #     job_end_time = time.time()*1000
            duration = job.duration()/HOUR_UNIT_TIME_MILL_SECOND
            #保留两位小数
            duration = float("{:.2f}".format(duration))
            jobs_hours[job.name()] = dict(name = job.name(),
                                          username = job.user(),
                                          begintime = job.completedTime(),
                                          value = duration)

        return jobs_hours

    def _get_userid_email_map(self, top_jobs_list):
        user_id_list =[]
        for job_info in top_jobs_list:
            if job_info["username"] not in user_id_list:
                user_id_list.append(job_info["username"])

        #user_id 转account
        users_info = inner_db.session.query(PlatformUsers.id, PlatformUsers.account, PlatformUsers.email)\
        .filter(PlatformUsers.id.in_(user_id_list)).all()

        #转换用户名称
        users_map_info = {}
        for user in users_info:
            user_id = user[0]
            user_account = user[1]
            user_email = user[2]
            users_map_info[user_id] = dict(email= user_email, account =user_account)

        return users_map_info

    #获取top k 个任务
    def _test_top_k(self, k, jobs_hours_map):
        top_k = []
        for job_name in jobs_hours_map:
            job_add_info = jobs_hours_map[job_name]
            if len(top_k) < k:
                top_k.append(job_add_info)
            else:
                min = top_k[0]
                min_index = index = 0
                while index < len(top_k):
                    if top_k[index]["value"] < min["value"]:
                        min = top_k[index]
                        min_index = index
                    index += 1

                if min["value"] < jobs_hours_map[job_name]['value']:
                   top_k[min_index] = job_add_info

        return sorted(top_k, key=lambda x:x["value"], reverse=True)

    def _get_top_durtaion_jobs(self, records):
        jobs_hours = self._get_jobs_durtaion_info(records)

        #获取前TOP_NUM时长任务
        top_jobs_list = self._test_top_k(TOP_NUM, jobs_hours)

        #user_id email account 映射关系
        users_map_info = self._get_userid_email_map(top_jobs_list)

        #将user_id 转为 account
        for top_job_info in top_jobs_list:
            user_id = top_job_info["username"]
            top_job_info["username"] = users_map_info[user_id]["account"]

        return top_jobs_list
